<?php


namespace backend\components\adapter;

use Yii;
use backend\components\Installer;
use backend\components\InstallerAdapter;
use yii\helpers\FileHelper;

/**
 * description of PluginAdapter
 *
 * @author FireLoong
 */
class PluginAdapter extends InstallerAdapter
{

    /**
     * @var object `<files>` element of the old extension manifest
     */
    protected $oldFiles = null;

    /**
     * Method to do any prechecks and setup the install paths for the extension
     * @return void
     */
    protected function setupInstallPaths()
    {
        $this->group = (string)$this->manifest->attributes()->group;

        if (empty($this->element) && empty($this->group)) {
            $param = Yii::t('installer', strtoupper($this->route));
            throw new \RuntimeException(Yii::t('installer', 'ABORT_PLG_INSTALL_NO_FILE', $param));
        }

        $this->parent->setPath('extension_root', Yii::getAlias('@common/plugins/' . $this->group . '/' . $this->element));
    }

    /**
     * Method to check if the extension is already present in the database
     * @return void
     */
    protected function checkExistingExtension()
    {
        try {
            $this->currentExtensionId = $this->extension->findOne([
                'type' => $this->type,
                'element' => $this->element,
                'folder' => $this->group
            ]);
        } catch (\RuntimeException $e) {
            $params = [
                'action' => Yii::t('installer', strtoupper($this->route)),
                'error' => $e->getMessage()
            ];
            throw new \RuntimeException(Yii::t('installer', 'ABORT_ROLLBACK', $params), $e->getCode(), $e);
        }
    }

    /**
     * Method to create the extension root path if necessary
     * @return void
     * @throws Yii\base\Exception
     */
    protected function createExtensionRoot()
    {
        parent::createExtensionRoot();
        if ($this->route === 'update') {
            $tmpInstaller = new Installer();
            $tmpInstaller->setPath('source', $this->parent->getPath('extension_root'));
            if ($tmpInstaller->findManifest()) {
                $oldManifest = $tmpInstaller->getManifest();
                $this->oldFiles = $oldManifest->files;
            }
        }
    }

    /**
     * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file
     * @return void
     * @throws  \RuntimeException
     * @throws \yii\base\ErrorException
     */
    protected function copyBaseFiles()
    {
        if ($this->parent->parseFiles($this->manifest->files, null, $this->oldFiles) === false) {
            $param = Yii::t('installer', strtoupper($this->route));
            throw new \RuntimeException(Yii::t('installer', 'ABORT_PLG_COPY_FILES', $param));
        }
    }

    /**
     * Method to parse optional tags in the manifest
     * @return void
     */
    protected function parseOptionalTags()
    {
        $this->parent->parseMessages($this->manifest->messages, 'backend');
    }

    /**
     * Method to store the extension to the database
     * @return void
     * @throws \RuntimeException
     */
    protected function storeExtension()
    {
        if ($this->currentExtensionId) {
            $this->extension = $this->currentExtensionId;
        } else {
            $this->extension->type = 'plugin';
            $this->extension->ordering = 0;
            $this->extension->element = $this->element;
            $this->extension->folder = $this->group;
            $this->extension->enabled = 0;
            $this->extension->protected = 0;
            $this->extension->client_id = 0;
            $this->extension->status = 1;

            if ($this->group === 'editors') {
                $this->extension->enabled = 1;
            }
        }
        $this->extension->name = $this->name;
        $this->extension->params = $this->extension->params ?: $this->parent->getParams();
        $this->extension->manifest_cache = $this->parent->generateManifestCache();

        if (!$this->extension->save()) {
            $params = [
                'action' => Yii::t('installer', strtoupper($this->route)),
                'error' => $this->parent->errorsToString($this->extension->getErrors())
            ];
            throw new \RuntimeException(Yii::t('installer', 'ABORT_ROLLBACK', $params));
        }
        $this->parent->pushStep(['type' => 'extension', 'id' => $this->extension->id]);
    }

    /**
     * Get the filtered extension element from the manifest
     * @param string $element Optional element name to be converted
     * @return string
     */
    public function getElement($element = null)
    {
        if (!$element) {
            if (count($this->manifest->files->children())) {
                $type = (string)$this->manifest->attributes()->type;
                foreach ($this->manifest->files->children() as $child) {
                    if ((string)$child->attributes()->$type) {
                        $element = (string)$child->attributes()->$type;
                        break;
                    }
                }
            }
        }
        return $element;
    }

    /**
     * 卸载插件
     * @param object $extension 扩展对象数据
     * @return bool
     * @throws \Throwable
     * @throws \yii\base\ErrorException
     * @throws \yii\db\Exception
     */
    public function uninstall($extension)
    {
        $session = Yii::$app->session;
        $retval = true;
        if ($extension->protected) {
            $extensionName = Yii::t($extension->manifest_cache['langCat'], $extension->name);
            $session->addFlash('warning', Yii::t('installer', 'ERROR_PLG_UNINSTALL_WARN_CORE_PLUGIN', $extensionName));
            return false;
        }

        if ($extension->package_id) {
            $extensionName = Yii::t($extension->manifest_cache['langCat'], $extension->name);
            $session->addFlash('warning', Yii::t('installer', 'ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $extensionName));
            return false;
        }

        if (trim($extension->folder) === '') {
            $session->addFlash('warning', Yii::t('installer', 'ERROR_PLG_UNINSTALL_FOLDER_FIELD_EMPTY'));
            return false;
        }

        $pluginPathAlias = '@common/plugins/' . $extension->folder . '/' . $extension->element;
        $this->parent->setPath('extension_root', Yii::getAlias($pluginPathAlias));
        $this->parent->setPath('source', $this->parent->getPath('extension_root'));

        $this->parent->findManifest();

        $this->manifest = $this->parent->manifest;

        if (isset($this->manifest->uninstall->sql)) {
            try {
                $this->parent->parseSQL($this->manifest->uninstall->sql);
            } catch (\yii\db\Exception $e) {
                $this->parent->abort(Yii::t('installer', 'ABORT_PLG_UNINSTALL_SQL_ERROR', $e->getMessage()));
                return false;
            }
        }

        if (!$this->parent->removeFiles($this->manifest->files)) {
            $retval = false;
        }
        if (!$this->parent->removeFiles($this->manifest->media)) {
            $retval = false;
        }
        if (!$this->parent->removeFiles($this->manifest->messages, 'backend')) {
            $retval = false;
        }

        $extension->delete();

        FileHelper::removeDirectory($this->parent->getPath('extension_root'));

        return $retval;
    }
}
